// Author: dnorlov@google.com (Dmitry Orlov)

#include "command.h"

namespace assembler {

const int CommandArgumentInfo::ArgumentCount[NUM_COMMAND_TYPE] = {
  0,  // INVALID_COMMAND
  2,  // MOV
  2,  // ADD
  2,  // SUB
  2,  // MULT
  2,  // DIV
  1,  // CALL
  0,  // RET
  1,  // PUSH
  1   // POP
};

const int CommandArgumentInfo::Arguments[NUM_COMMAND_TYPE][2] = {
  {NO_ARGUMENT, NO_ARGUMENT},               // INVALID_COMMAND
  {ARGUMENT_REGISTER, ARGUMENT_REGISTER + ARGUMENT_CONSTANT},  // MOV
  {ARGUMENT_REGISTER, ARGUMENT_REGISTER + ARGUMENT_CONSTANT},  // ADD
  {ARGUMENT_REGISTER, ARGUMENT_REGISTER + ARGUMENT_CONSTANT},  // SUB
  {ARGUMENT_REGISTER, ARGUMENT_REGISTER + ARGUMENT_CONSTANT},  // MULT
  {ARGUMENT_REGISTER, ARGUMENT_REGISTER + ARGUMENT_CONSTANT},  // DIV
  {ARGUMENT_FUNCTION_NAME, NO_ARGUMENT},                       // CALL
  {NO_ARGUMENT, NO_ARGUMENT},                                  // RET
  {ARGUMENT_REGISTER + ARGUMENT_CONSTANT, NO_ARGUMENT},        // PUSH
  {ARGUMENT_REGISTER, NO_ARGUMENT}                             // POP
};

Command::Command(CommandType type):
  type_(type) {
  arg1_.type = NO_ARGUMENT;
  arg2_.type = NO_ARGUMENT;
  if (CommandArgumentInfo::ArgumentCount[type] != 0) {
    type_ = INVALID_COMMAND;
  }
}

Command::Command(CommandType type, const CommandArgument &arg1)
  : type_(type), arg1_(arg1) {
  arg2_.type = NO_ARGUMENT;
  if (CommandArgumentInfo::ArgumentCount[type] != 1) {
    type_ = INVALID_COMMAND;
    return;
  }
  if ((CommandArgumentInfo::Arguments[type][0] & arg1_.type) == 0) {
    type_ = INVALID_COMMAND;
  }
}

Command::Command(CommandType type, const CommandArgument &arg1,
                 const CommandArgument &arg2)
    : type_(type), arg1_(arg1), arg2_(arg2) {
  if (CommandArgumentInfo::ArgumentCount[type] != 2) {
    type_ = INVALID_COMMAND;
    return;
  }
  if ((CommandArgumentInfo::Arguments[type][0] & arg1_.type) == 0) {
    type_ = INVALID_COMMAND;
  }
  if ((CommandArgumentInfo::Arguments[type][1] & arg2_.type) == 0) {
    type_ = INVALID_COMMAND;
  }
}

}  // namespace assembler
